﻿using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using Emgu.CV;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WinFormsApp1
{
    public class WhiteBorderMatcher
    {
        /// <summary>
        /// 匹配带有白色边框的目标区域
        /// </summary>
        public static List<Rectangle> FindWithWhiteBorder(
            Mat source,
            Mat template,
            double matchThreshold = 0.85,
            int borderThickness = 5,
            int whiteThreshold = 230)
        {
            // 步骤1：预处理源图像，查找白色边框候选区域
            List<Rectangle> whiteAreas = FindWhiteBorderRegions(source, borderThickness, whiteThreshold);

            List<Rectangle> results = new List<Rectangle>();

            // 步骤2：在候选区域内进行模板匹配
            foreach (var area in whiteAreas)
            {
                using (Mat roi = new Mat(source, area))
                {
                    Mat matchResult = new Mat();
                    CvInvoke.MatchTemplate(roi, template, matchResult, TemplateMatchingType.CcoeffNormed);

                    double minVal=0, maxVal=0;
                    Point minLoc=Point.Empty, maxLoc= Point.Empty;
                    CvInvoke.MinMaxLoc(matchResult, ref minVal, ref maxVal, ref minLoc, ref maxLoc);

                    if (maxVal >= matchThreshold)
                    {
                        Rectangle matchRect = new Rectangle(
                            area.X + maxLoc.X,
                            area.Y + maxLoc.Y,
                            template.Width,
                            template.Height);

                        // 二次验证边框完整性
                        if (VerifyBorderIntegrity(source, matchRect, borderThickness, whiteThreshold))
                        {
                            results.Add(matchRect);
                        }
                    }
                }
            }
            return results;
        }

        /// <summary>
        /// 查找所有可能包含白色边框的区域
        /// </summary>
        private static List<Rectangle> FindWhiteBorderRegions(Mat image, int borderThickness, int whiteThreshold)
        {
            List<Rectangle> regions = new List<Rectangle>();

            using (Mat gray = new Mat())
            using (Mat edges = new Mat())
            {
                // 转换为灰度图并进行边缘检测
                CvInvoke.CvtColor(image, gray, ColorConversion.Bgr2Gray);
                CvInvoke.Canny(gray, edges, 100, 200);

                // 膨胀操作增强边框特征
                Mat kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle,
                    new Size(borderThickness * 2 + 1, borderThickness * 2 + 1),
                    new Point(borderThickness, borderThickness));

                CvInvoke.Dilate(edges, edges, kernel, new Point(-1, -1), 1, BorderType.Default, default(MCvScalar));

                // 查找轮廓
                VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
                CvInvoke.FindContours(edges, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);

                // 筛选白色边框区域
                for (int i = 0; i < contours.Size; i++)
                {
                    Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);

                    // 扩展检测区域
                    rect.Inflate(borderThickness * 2, borderThickness * 2);
                    rect.Intersect(new Rectangle(Point.Empty, image.Size));

                    // 颜色验证
                    if (IsWhiteBorder(image, rect, borderThickness, whiteThreshold))
                    {
                        regions.Add(rect);
                    }
                }
            }
            return regions;
        }

        /// <summary>
        /// 验证边框的完整性
        /// </summary>
        private static bool VerifyBorderIntegrity(Mat image, Rectangle rect, int thickness, int whiteThreshold)
        {
            // 定义四个检测区域：上、下、左、右边框
            Rectangle[] borderAreas = {
            new Rectangle(rect.X, rect.Y, rect.Width, thickness), // 上
            new Rectangle(rect.X, rect.Bottom - thickness, rect.Width, thickness), // 下
            new Rectangle(rect.X, rect.Y, thickness, rect.Height), // 左
            new Rectangle(rect.Right - thickness, rect.Y, thickness, rect.Height)  // 右
        };

            foreach (var area in borderAreas)
            {
                using (Mat roi = new Mat(image, area))
                using (Mat hsv = new Mat())
                {
                    CvInvoke.CvtColor(roi, hsv, ColorConversion.Bgr2Hsv);

                    // 白色在HSV空间的判定（低饱和度+高亮度）
                    Mat mask = new Mat();
                    CvInvoke.InRange(hsv,
                        new ScalarArray(new MCvScalar(0, 0, 240)),
                        new ScalarArray(new MCvScalar(180, 30, 255)),
                        mask);

                    double whiteRatio = CvInvoke.CountNonZero(mask) / (double)mask.Total;
                    if (whiteRatio < 0.85) return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 判断是否为有效白色边框
        /// </summary>
        private static bool IsWhiteBorder(Mat image, Rectangle rect, int thickness, int whiteThreshold)
        {
            // 提取边框区域
            Rectangle borderRect = new Rectangle(
                rect.X - thickness,
                rect.Y - thickness,
                rect.Width + thickness * 2,
                rect.Height + thickness * 2);

            borderRect.Intersect(new Rectangle(Point.Empty, image.Size));

            using (Mat roi = new Mat(image, borderRect))
            using (Mat diff = new Mat())
            {
                // 创建纯白色对比图像
                Mat whiteMat = new Mat(roi.Size, roi.Depth, roi.NumberOfChannels);
                whiteMat.SetTo(new MCvScalar(255, 255, 255));

                // 计算差异
                CvInvoke.AbsDiff(roi, whiteMat, diff);

                // 转换到HSV空间计算颜色差异
                Mat hsvDiff = new Mat();
                CvInvoke.CvtColor(diff, hsvDiff, ColorConversion.Bgr2Hsv);

                // 分割通道
                Mat[] channels = hsvDiff.Split();

                // 计算饱和度通道的差异（白色饱和度应接近0）
                double saturationDiff = CvInvoke.Mean(channels[1]).V0;

                // 计算亮度通道的差异（白色亮度应接近255）
                double valueDiff = 255 - CvInvoke.Mean(channels[2]).V0;

                return saturationDiff < 20 && valueDiff < 15;
            }
        }

        // 使用示例
        public static void Main2(string b,string s)
        {
            using (Mat source = CvInvoke.Imread(b))
            using (Mat template = CvInvoke.Imread(s))
            {
                var matches = FindWithWhiteBorder(source, template);

                // 绘制所有匹配结果
                foreach (var rect in matches)
                {
                    CvInvoke.Rectangle(source, rect, new MCvScalar(0, 255, 0), 3);
                }

                CvInvoke.Imwrite("result.jpg", source);
                Console.WriteLine($"找到 {matches.Count} 个匹配目标");
            }
        }
    }
}
